package org.charles.zhifou.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.charles.zhifou.common.exception.BusinessException;
import org.charles.zhifou.common.exception.ThrowUtils;
import org.charles.zhifou.common.response.ResponseCodeEnum;
import org.charles.zhifou.enums.ReviewStatusEnum;
import org.charles.zhifou.enums.UserRoleEnum;
import org.charles.zhifou.mapper.UserAnswerMapper;
import org.charles.zhifou.model.dto.statistic.AppAnswerCountDTO;
import org.charles.zhifou.model.dto.statistic.AppAnswerResultCountDTO;
import org.charles.zhifou.model.entity.App;
import org.charles.zhifou.model.entity.User;
import org.charles.zhifou.model.entity.UserAnswer;
import org.charles.zhifou.scoring.ScoringStrategyExecutor;
import org.charles.zhifou.service.AppService;
import org.charles.zhifou.service.UserAnswerService;
import org.charles.zhifou.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.util.List;

/**
* @author charles
* @description 针对表【user_answer(用户答题记录)】的数据库操作Service实现
* @createDate 2024-08-06 09:11:36
*/
@Service
public class UserAnswerServiceImpl extends ServiceImpl<UserAnswerMapper, UserAnswer>
    implements UserAnswerService {

    @Resource
    private AppService appService;

    @Resource
    private UserService userService;

    @Resource
    private ScoringStrategyExecutor scoringStrategyExecutor;
    @Autowired
    private UserAnswerMapper userAnswerMapper;

    @Override
    public Long addUserAnswer(UserAnswer userAnswer) {
        // 判断 App 是否存在
        App app = appService.getById(userAnswer.getAppId());
        ThrowUtils.throwIf(app == null, ResponseCodeEnum.PARAMS_ERROR, "应用不存在");

        // 判断应用是否已经过审
        ThrowUtils.throwIf(app.getReviewStatus() != ReviewStatusEnum.PASSED, ResponseCodeEnum.PARAMS_ERROR, "应用未过审");

        // 保存进数据库: 使用唯一主键实现幂等性
        try {
            boolean isSuccessful = this.save(userAnswer);
            ThrowUtils.throwIf(!isSuccessful, ResponseCodeEnum.OPERATION_ERROR, "数据库操作失败");
        } catch (DuplicateKeyException e) {
            throw new BusinessException(ResponseCodeEnum.PARAMS_ERROR, "当前回答 id 已提交, 请勿重复提交");
        }

        return userAnswer.getId();
    }

    /**
     * 评分
     * @param userAnswer 用户答案 (评分结果直接写在里面)
     */
    @Override
    public void doScore(UserAnswer userAnswer) throws Exception {
        // 获取对应 App
        App app = appService.getById(userAnswer.getAppId());

        // 应用类型与评分策略不可为空
        if (app.getAppType() == null || app.getScoringStrategy() == null) {
            throw new BusinessException(ResponseCodeEnum.PARAMS_ERROR, "应用类型或评分策略为空");
        }

        scoringStrategyExecutor.doScore(userAnswer, app);
    }

    @Override
    public boolean removeUserAnswerById(Long id) {
        // 判断回答是否存在
        UserAnswer userAnswerToDelete = this.getById(id);
        ThrowUtils.throwIf(userAnswerToDelete == null, ResponseCodeEnum.PARAMS_ERROR, "回答不存在");

        // 仅本人或管理员可删除
        User loginUser = userService.getLoginUser();
        if (!userAnswerToDelete.getUserId().equals(loginUser.getId()) && !UserRoleEnum.ADMIN.equals(loginUser.getUserRole())) {
            throw new BusinessException(ResponseCodeEnum.NO_AUTH_ERROR);
        }

        return this.removeById(id);
    }

    @Override
    public boolean updateUserAnswer(UserAnswer userAnswer) {
        // 判断回答是否存在
        UserAnswer userAnswerToUpdate = this.getById(userAnswer.getId());
        ThrowUtils.throwIf(userAnswerToUpdate == null, ResponseCodeEnum.PARAMS_ERROR, "回答不存在");

        // 如果应用 id 存在, 则应用必须也存在
        if (userAnswer.getAppId() != null) {
            App app = appService.getById(userAnswer.getAppId());
            ThrowUtils.throwIf(app == null, ResponseCodeEnum.PARAMS_ERROR, "应用不存在");
        }

        return this.updateById(userAnswer);
    }

    @Override
    public boolean editUserAnswer(UserAnswer userAnswer) {
        // 判断回答是否存在
        UserAnswer userAnswerToEdit = this.getById(userAnswer.getId());
        ThrowUtils.throwIf(userAnswerToEdit == null, ResponseCodeEnum.PARAMS_ERROR, "回答不存在");

        // 如果应用 id 存在, 则应用必须也存在
        if (userAnswer.getAppId() != null) {
            App app = appService.getById(userAnswer.getAppId());
            ThrowUtils.throwIf(app == null, ResponseCodeEnum.PARAMS_ERROR, "应用不存在");
        }

        // 仅本人或管理员可修改
        User loginUser = userService.getLoginUser();
        if (!userAnswerToEdit.getUserId().equals(loginUser.getId()) && !UserRoleEnum.ADMIN.equals(loginUser.getUserRole())) {
            throw new BusinessException(ResponseCodeEnum.NO_AUTH_ERROR);
        }

        return this.updateById(userAnswer);
    }

    @Override
    public List<AppAnswerCountDTO> doAppAnswerCount() {
        return userAnswerMapper.doAppAnswerCount();
    }

    @Override
    public List<AppAnswerResultCountDTO> doAppAnswerResultCount(Long appId) {
        return userAnswerMapper.doAppAnswerResultCount(appId);
    }
}